
import AMF from './amf-parser'
import SPSParser from './sps-parser'
import DemuxErrors from './demux-errors'
import MediaInfo from '../core/media-info'

function Swap16(src) {
    return (((src >>> 8) & 0xFF) |
            ((src & 0xFF) << 8));
}

function Swap32(src) {
    return (((src & 0xFF000000) >>> 24) |
            ((src & 0x00FF0000) >>> 8)  |
            ((src & 0x0000FF00) << 8)   |
            ((src & 0x000000FF) << 24));
}

function ReadBig32(array, index) {
    return ((array[index] << 24)     |
            (array[index + 1] << 16) |
            (array[index + 2] << 8)  |
            (array[index + 3]));
}

class FLVDemuxer {
    constructor(probeData, config) {
        this._config = config

        this._onError = null
        this._mediaInfo = null
        this._onMetaDataArrived = null
        this._onScriptDataArrived = null
        this._onDataAvailabe = null

        this._dataOffset = probeData.dataOffset
        this._firstParse = true
        this._dispatch = false

        this._hasAudio = probeData.hasAudioTrack
        this._hasVideo = probeData.hasVideoTrack

        this._hasAudioFlagOverrided = false
        this._hasVideoFlagOverrided = false

        this._audioInitialMetadataDispatched = false
        this._videoInitialMetadataDispatched = false

        this._mediaInfo = new MediaInfo()
        this._mediaInfo.hasAudio = this._hasAudio
        this._mediaInfo.hasVideo = this._hasVideo
        this._metadata = null
        this._audioMetadata = null
        this._videoMetadata = null

        this._naluLengthSize = 4
        this._timestampBase = 0 // int32, in milliseconds
        this._timescale = 1000
        this._duration = 0
        this._durationOverrided = false
        this._referenceFrameRate = {
            fixed: true,
            fps: 23.976,
            fps_num: 23976,
            fps_den: 1000,
        }

        this._flvSoundRateTable = [
            5500, 11025, 22050, 44100, 48000
        ]
        this._mpegSamplingRates = [
            96000, 88200, 64000, 48000, 44100, 32000,
            24000, 22050, 16000, 12000, 11025, 8000, 7350
        ]

        this._mpegAudioV10SampleRateTable = [44100, 48000, 32000, 0]
        this._mpegAudioV20SampleRateTable = [22050, 24000, 16000, 0]
        this._mpegAudioV25SampleRateTable = [11025, 12000, 8000, 0]

        this._mpegAudioL1BitRateTable = [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1];
        this._mpegAudioL2BitRateTable = [0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, -1];
        this._mpegAudioL3BitRateTable = [0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, -1];

        this._videoTrack = {type: 'video', id: 1, sequenceNumber: 0,    samples: [], length: 0}
        this._audioTrack = {type: 'audio', id: 2, sequenceNumber: 0, samples: [], length: 0}

        this._littleEndian = (function () {
            let buf = new ArrayBuffer(2);
            (new DataView(buf)).setInt16(0, 256, true);  // little-endian write
            return (new Int16Array(buf))[0] === 256;  // platform-spec read, if equal then LE
        })();

    }

    destroy(){
        this._mediaInfo = null
        this._metadata = null
        this._audioMetadata = null
        this._videoMetadata = null
        this._videoTrack = null
        this._audioTrack = null

        this._onError = null
        this._onMediaInfo = null
        this._onMetaDataArrived = null
        this._onScriptDataArrived = null
        this._onTrackMetadata = null
        this._onDataAvailabe = null
    }

    static probe(buffer) {
        let data = new Uint8Array(buffer)
        let mismatch = {match: false}

        if (
            data[0] !== 0x46 ||
            data[1] !== 0x4c ||
            data[2] !== 0x56 ||
            data[3] !== 0x01
        ) {
            return mismatch
        }
    }
}